package com.xtianzhuang.www.utils;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class Common {
	protected static final Logger log = LoggerFactory.getLogger(Common.class);
	private static Common common;

	public Common() {
	}

	public static Common getInstance() {
		if (common == null) {
			common = new Common();
		}

		return common;
	}

	public String getTimestampFormat(String value) {
		switch (value.length()) {
			case 4:
				return "yyyy";
			case 5:
			case 9:
			case 11:
			case 12:
			case 14:
			case 15:
			case 17:
			case 18:
			case 20:
			default:
				return null;
			case 6:
				return "yyyyMM";
			case 7:
				return "yyyy-MM";
			case 8:
				return "yyyyMMdd";
			case 10:
				return "yyyy-MM-dd";
			case 13:
				return "yyyy-MM-dd HH";
			case 16:
				return "yyyy-MM-dd HH:mm";
			case 19:
				return "yyyy-MM-dd HH:mm:ss";
			case 21:
				return "yyyy-MM-dd HH:mm:ss.S";
		}
	}

	public String getMatchStr(String str, String regex) {
		List result = this.getMatchArray(str, regex);
		return result.size() == 0 ? null : (String) result.get(0);
	}

	public List getMatchArray(String str, String regex) {
		List result = new ArrayList();
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(str);

		while (matcher.find()) {
			result.add(matcher.group());
		}

		return result;
	}

	public boolean isMatches(String str, String regex) {
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(str);
		return matcher.matches();
	}

	public String trimPrefix(String str, String prefix) {
		return str.startsWith(prefix) ? str.substring(prefix.length()) : str;
	}

	public String trimSuffix(String str, String suffix) {
		return str.endsWith(suffix) ? str.substring(0, str.length() - 1) : str;
	}

	public String getStrByArray(String[] array) {
		return this.getStrByArray(array, ",");
	}

	public String getStrByArray(String[] array, String split) {
		StringBuilder str = new StringBuilder();

		for (int i = 0; i < array.length; ++i) {
			str.append(array[i] + (i != array.length - 1 ? split : ""));
		}

		return str.toString();
	}

	public String encodeCharset(String charSet) {
		String set = null;

		try {
			set = new String(charSet.getBytes("GBK"), "ISO8859_1");
			return set;
		} catch (UnsupportedEncodingException var4) {
			throw new RuntimeException(var4);
		}
	}

	public String decodeCharset(String charSet) {
		String set = null;

		try {
			set = new String(charSet.getBytes("ISO8859_1"), "GBK");
			return set;
		} catch (UnsupportedEncodingException var4) {
			throw new RuntimeException(var4);
		}
	}

	public Date encodeTimestamp(String timeStr) {
		if (timeStr != null && !"".equals(timeStr)) {
			String format = this.getTimestampFormat(timeStr);
			return StringUtils.isEmpty(format) ? null : this.encodeTimestamp(format, timeStr);
		} else {
			return null;
		}
	}

	public Date encodeTimestamp(String format, String timeStr) {
		Date date = null;
		if (null != timeStr && !"".equals(timeStr)) {
			if (format.length() != timeStr.length()) {
				format = this.getTimestampFormat(timeStr);
			}

			SimpleDateFormat sdf = new SimpleDateFormat(format);

			try {
				date = new Timestamp(sdf.parse(timeStr).getTime());
				return date;
			} catch (ParseException var6) {
				throw new RuntimeException(var6);
			}
		} else {
			return null;
		}
	}

	public String decodeTimeStr(String format, String timeStr) {
		Date time = this.encodeTimestamp(format, timeStr);
		return this.decodeTimestamp(format, time);
	}

	public String decodeTimestamp(String format, Date time) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(time);
	}

	public Date getCurrentTime() {
		return new Timestamp(System.currentTimeMillis());
	}

	public String getSysTime() {
		return this.decodeTimestamp("yyyy-MM-dd HH:mm:ss", new Timestamp(System.currentTimeMillis()));
	}

	public String getSysDate() {
		return this.decodeTimestamp("yyyy-MM-dd", new Timestamp(System.currentTimeMillis()));
	}

	public String getLastDay() {
		return this.getLastDay(this.getSysDate());
	}

	public String getLastDay(String timestr) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(this.encodeTimestamp(timestr));
		cal.set(5, cal.getActualMaximum(5));
		SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
		return dateformat.format(cal.getTime());
	}

	public String getPrevDayByCurrDate() {
		Calendar cal = Calendar.getInstance();
		cal.add(5, -1);
		SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
		return dateformat.format(cal.getTime());
	}

	public String getPrevMonthFirstDay() {
		Calendar cal = Calendar.getInstance();
		cal.add(2, -1);
		cal.set(5, 1);
		SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
		return dateformat.format(cal.getTime());
	}

	public String formatDecimal(String format, double decimal) {
		DecimalFormat df = new DecimalFormat(format);
		return df.format(decimal);
	}

	public URL getClassResource(String file) {
		URL url = this.getClass().getClassLoader().getResource(file);
		if (url == null) {
			this.error("file " + file + " not exist!");
		}

		return url;
	}

	public int getCharLength(String value) {
		char[] chars = value.toCharArray();
		int charlen = 0;

		for (int i = 0; i < chars.length; ++i) {
			if (chars[i] > 128) {
				charlen += 2;
			} else {
				++charlen;
			}
		}

		return charlen;
	}

	public int getCharLength(String value, int length) {
		char[] chars = value.toCharArray();
		if (chars.length < length) {
			length = chars.length;
		}

		int charidx = 0;

		for (int charlen = 0; charlen < length; ++charidx) {
			if (chars[charidx] > 128) {
				charlen += 2;
			} else {
				++charlen;
			}
		}

		return charidx;
	}

	public List getArrayByCodingStr(String namestr, String encodestr) {
		String[] encodename = namestr.split(",");
		int tablen = 4;
		int rowlen = 4;
		int collen = 3;
		int rows = Integer.parseInt(encodestr.substring(tablen, tablen + rowlen));
		String content = encodestr.substring(tablen + rowlen + collen);
		List dataset = new ArrayList();

		for (int i = 0; i < rows; ++i) {
			Map data = new HashMap();

			for (int j = 0; j < encodename.length; ++j) {
				int namelen = Integer.parseInt(content.substring(0, 4));
				content = content.substring(4);
				int vallen = this.getCharLength(content, namelen);
				String value = content.substring(0, vallen);
				content = content.substring(vallen);
				data.put(encodename[j], value);
			}

			dataset.add(data);
		}

		return dataset;
	}

	public Map putDataByEntity(Object entity) throws Exception {
		Map data = new HashMap();
		Method[] methods = entity.getClass().getDeclaredMethods();

		for (int i = 0; i < methods.length; ++i) {
			String methodName = methods[i].getName();
			if (methodName.startsWith("get")) {
				String paramName = methodName.substring(3, methodName.length());
				data.put(paramName, methods[i].invoke(entity, (Object[]) null));
			}
		}

		return data;
	}

	public Object putEntityByData(Object entity, Map data) throws Exception {
		Method[] methods = entity.getClass().getDeclaredMethods();

		for (int i = 0; i < methods.length; ++i) {
			Method method = methods[i];
			String methodName = method.getName();
			if (methodName.startsWith("set")) {
				Class methodType = method.getParameterTypes()[0];
				Object[] params = new Object[1];
				String paramName = methodName.substring(3, methodName.length()).toUpperCase();
				Object paramValue = data.get(paramName);
				if (paramValue != null) {
					params[0] = paramValue;
					if (String.class.isAssignableFrom(methodType)) {
						params[0] = paramValue;
					} else if (Date.class.isAssignableFrom(methodType)) {
						params[0] = this.encodeTimestamp((String) paramValue);
					} else if (Long.class.isAssignableFrom(methodType)) {
						params[0] = new Long(paramValue.toString());
					} else if (Integer.class.isAssignableFrom(methodType)) {
						params[0] = new Integer(paramValue.toString());
					} else if (Short.class.isAssignableFrom(methodType)) {
						params[0] = new Short(paramValue.toString());
					} else if (Double.class.isAssignableFrom(methodType)) {
						params[0] = new Double(paramValue.toString());
					} else if (Float.class.isAssignableFrom(methodType)) {
						params[0] = new Float(paramValue.toString());
					} else if (Boolean.class.isAssignableFrom(methodType)) {
						params[0] = new Boolean(paramValue.toString());
					}

					method.invoke(entity, params);
				}
			}
		}

		return entity;
	}

	public Object callBean(String class_name, String method_name) throws Exception {
		return this.callBean(class_name, method_name, (Object[]) null, (Class[]) null);
	}

	public Object callBean(String class_name, String method_name, Object[] params) throws Exception {
		return this.callBean(class_name, method_name, params, (Class[]) null);
	}

	public Object callBean(String class_name, String method_name, Object[] params, Class[] types) throws Exception {
		Class cls = Class.forName(class_name);
		Object instance = cls.newInstance();
		if (types == null) {
			types = new Class[params.length];
		}

		if (params != null && types != null) {
			for (int i = 0; i < types.length; ++i) {
				if (types[i] == null) {
					types[i] = params[i].getClass();
				}
			}
		}

		Method method = cls.getMethod(method_name, types);
		return method.invoke(instance, params);
	}

	public Object callBean(Object instance, String method_name, Object[] params, Class[] types) throws Exception {
		if (params != null && types != null) {
			for (int i = 0; i < types.length; ++i) {
				if (types[i] == null) {
					types[i] = params[i].getClass();
				}
			}
		}

		Method method = instance.getClass().getMethod(method_name, types);
		return method.invoke(instance, params);
	}



	public void error(String message) throws RuntimeException {
		RuntimeException exception = new RuntimeException(message);
		log.error(message);
		throw exception;
	}

	public void error(Exception e) throws RuntimeException {
		RuntimeException exception = new RuntimeException(e);
		log.error(e.getMessage(), exception);
		throw exception;
	}

	public void error(String message, Exception e) throws RuntimeException {
		RuntimeException exception = new RuntimeException(message, e);
		log.error(message, exception);
		throw exception;
	}

	public String[] getValues(Object value) {
		if (value == null) {
			return new String[0];
		} else {
			return value instanceof String[] ? (String[]) ((String[]) value) : new String[]{(String) value};
		}
	}

	public String toChineseMoney(String money) {
		if (money == null) {
			return null;
		} else {
			String prefix = money.startsWith("-") ? "负" : "";
			money = money.replaceAll("-", "");
			String[] part = money.split("\\.");
			String newchar = "";

			int i;
			String tmpnewchar;
			char perchar;
			for (i = part[0].length() - 1; i >= 0; --i) {
				if (part[0].length() > 10) {
					this.error("位数过大，无法计算");
				}

				tmpnewchar = "";
				perchar = part[0].charAt(i);
				switch (perchar) {
					case '0':
						tmpnewchar = "零" + tmpnewchar;
						break;
					case '1':
						tmpnewchar = "壹" + tmpnewchar;
						break;
					case '2':
						tmpnewchar = "贰" + tmpnewchar;
						break;
					case '3':
						tmpnewchar = "叁" + tmpnewchar;
						break;
					case '4':
						tmpnewchar = "肆" + tmpnewchar;
						break;
					case '5':
						tmpnewchar = "伍" + tmpnewchar;
						break;
					case '6':
						tmpnewchar = "陆" + tmpnewchar;
						break;
					case '7':
						tmpnewchar = "柒" + tmpnewchar;
						break;
					case '8':
						tmpnewchar = "捌" + tmpnewchar;
						break;
					case '9':
						tmpnewchar = "玖" + tmpnewchar;
				}

				switch (part[0].length() - i - 1) {
					case 0:
						tmpnewchar = tmpnewchar + "元";
						break;
					case 1:
						if (perchar != 0) {
							tmpnewchar = tmpnewchar + "拾";
						}
						break;
					case 2:
						if (perchar != 0) {
							tmpnewchar = tmpnewchar + "佰";
						}
						break;
					case 3:
						if (perchar != 0) {
							tmpnewchar = tmpnewchar + "仟";
						}
						break;
					case 4:
						tmpnewchar = tmpnewchar + "万";
						break;
					case 5:
						if (perchar != 0) {
							tmpnewchar = tmpnewchar + "拾";
						}
						break;
					case 6:
						if (perchar != 0) {
							tmpnewchar = tmpnewchar + "佰";
						}
						break;
					case 7:
						if (perchar != 0) {
							tmpnewchar = tmpnewchar + "仟";
						}
						break;
					case 8:
						tmpnewchar = tmpnewchar + "亿";
						break;
					case 9:
						tmpnewchar = tmpnewchar + "拾";
				}

				newchar = tmpnewchar + newchar;
			}

			if (money.indexOf(".") != -1) {
				if (part[1].length() > 2) {
					log.warn("小数点之后只能保留两位,系统将自动截断");
					part[1] = part[1].substring(0, 2);
				}

				for (i = 0; i < part[1].length(); ++i) {
					tmpnewchar = "";
					perchar = part[1].charAt(i);
					switch (perchar) {
						case '0':
							tmpnewchar = "零" + tmpnewchar;
							break;
						case '1':
							tmpnewchar = "壹" + tmpnewchar;
							break;
						case '2':
							tmpnewchar = "贰" + tmpnewchar;
							break;
						case '3':
							tmpnewchar = "叁" + tmpnewchar;
							break;
						case '4':
							tmpnewchar = "肆" + tmpnewchar;
							break;
						case '5':
							tmpnewchar = "伍" + tmpnewchar;
							break;
						case '6':
							tmpnewchar = "陆" + tmpnewchar;
							break;
						case '7':
							tmpnewchar = "柒" + tmpnewchar;
							break;
						case '8':
							tmpnewchar = "捌" + tmpnewchar;
							break;
						case '9':
							tmpnewchar = "玖" + tmpnewchar;
					}

					if (i == 0) {
						tmpnewchar = tmpnewchar + "角";
					}

					if (i == 1) {
						tmpnewchar = (part[1].charAt(0) == '0' ? "零" : "") + tmpnewchar + "分";
					}

					newchar = newchar + tmpnewchar;
				}
			}

			while (newchar.indexOf("零零") != -1) {
				newchar = newchar.replaceAll("零零", "零");
			}

			newchar = newchar.replaceAll("零亿", "亿");
			newchar = newchar.replaceAll("亿万", "亿");
			newchar = newchar.replaceAll("零万", "万");
			if (!newchar.startsWith("零元")) {
				newchar = newchar.replaceAll("零元", "元");
			}

			newchar = newchar.replaceAll("零角", "");
			newchar = newchar.replaceAll("零分", "");
			if (newchar.charAt(newchar.length() - 1) == 20803 || newchar.charAt(newchar.length() - 1) == '角') {
				newchar = newchar + "整";
			}

			return prefix + newchar;
		}
	}

	public Object reflectInvoke(Object bean, String funcName, Object[] params, Class[] types) throws Exception {
		Object ret = null;
		Class[] Params = new Class[params.length];

		for (int i = 0; i < params.length; ++i) {
			if (types != null && types[i] != null) {
				Params[i] = types[i];
			} else if (params[i] != null) {
				Params[i] = params[i].getClass();
			}
		}

		Method method = bean.getClass().getMethod(funcName, Params);
		ret = method.invoke(bean, params);
		return ret;
	}

	public String getPartitionId(String id) {
		return this.getPartitionId(id, 4);
	}

	public String getPartitionId(String id, int length) {
		return String.valueOf(Long.parseLong(id) % ((int) Math.pow(10.0D, length)));
	}

	public boolean equalsNVL(Object obj1, Object obj2) {
		if (obj1 == null && obj2 == null) {
			return true;
		} else {
			return obj1 != null && obj2 != null && obj1.equals(obj2);
		}
	}

	public int hashCodeNVL(Object o) {
		return o == null ? 0 : o.hashCode();
	}

	public String getStackTrace(Object e) {
		return this.getStackTrace((Throwable) e, 0);
	}

	public String getStackTrace(Throwable e, int maxLength) {
		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		e.printStackTrace(pw);
		String str = sw.toString();
		if (maxLength == 0) {
			return str;
		} else {
			int charLength = this.getCharLength(str, maxLength);
			return str.substring(0, charLength);
		}
	}


	public Field getFieldByFieldName(Object obj, String fieldName) {
		Class superClass = obj.getClass();

		while (superClass != Object.class) {
			try {
				return superClass.getDeclaredField(fieldName);
			} catch (NoSuchFieldException var5) {
				superClass = superClass.getSuperclass();
			}
		}

		return null;
	}

	public Object getValueByFieldName(Object obj, String fieldName) throws Exception {
		String methodName = "get" + this.toUpperCaseFirstOne(fieldName);

		try {
			obj.getClass().getMethod(methodName, (Class[]) null);
		} catch (Exception var5) {
			return null;
		}

		return this.callBean(obj, methodName, (Object[]) null, (Class[]) null);
	}

	public void setValueByFieldName(Object obj, String fieldName, Object value) throws Exception {
		String methodName = "set" + this.toUpperCaseFirstOne(fieldName);
		Field field = null;

		try {
			field = obj.getClass().getDeclaredField(fieldName);
			obj.getClass().getMethod(methodName, field.getType());
		} catch (Exception var7) {
			return;
		}

		this.callBean(obj, methodName, new Object[]{value}, new Class[]{field.getType()});
	}

	public String toLowerCaseFirstOne(String s) {
		return Character.isLowerCase(s.charAt(0)) ? s : Character.toLowerCase(s.charAt(0)) + s.substring(1);
	}

	public String toUpperCaseFirstOne(String s) {
		return Character.isUpperCase(s.charAt(0)) ? s : Character.toUpperCase(s.charAt(0)) + s.substring(1);
	}

	public String getUniqeName() {
		return String.valueOf(System.currentTimeMillis()) + Math.abs((new Random()).nextInt());
	}

	public boolean isBasicType(Class<?> clazz) {
		return String.class.isAssignableFrom(clazz) || Number.class.isAssignableFrom(clazz)
				|| Boolean.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz);
	}

	public String replaceBlank(String str) {
		Pattern p = Pattern.compile("\\s*|\t|\r|\n");
		Matcher m = p.matcher(str);
		return m.replaceAll("");
	}

	public String transParamDecode(String param, String charset) {
		if (param == null) {
			return null;
		} else {
			try {
				return URLDecoder.decode(param, charset).trim();
			} catch (UnsupportedEncodingException var4) {
				return null;
			}
		}
	}

	public HttpServletRequest getContextRequest() {
		ServletRequestAttributes ra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = ra.getRequest();
		return request;
	}

	public List[] getSubLists(List list, int sub) {
		List[] lists = null;
		if (list.size() > 0) {
			int subNums = list.size() / sub > 0 ? list.size() / sub + (list.size() % sub == 0 ? 0 : 1) : 1;
			lists = new List[subNums];

			for (int i = 0; i < subNums; ++i) {
				List subList = null;
				if (i != subNums - 1) {
					subList = list.subList(i * sub, (i + 1) * sub);
				} else {
					subList = list.subList(i * sub, list.size());
				}

				lists[i] = subList;
			}
		}

		return lists;
	}

	public boolean isAjaxRequest(HttpServletRequest request) {
		String header = request.getHeader("X-Requested-With");
		boolean isAjax = "XMLHttpRequest".equalsIgnoreCase(header);
		return isAjax;
	}

	public String getErrorInfo(String errorInfo) {
		if (StringUtils.isBlank(errorInfo)) {
			return "";
		} else {
			if (errorInfo.startsWith("java.lang.RuntimeException:")) {
				errorInfo = errorInfo.substring("java.lang.RuntimeException:".length());
			}

			return errorInfo.replaceAll("\\n", "<br/>").replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
		}
	}

	public String getRandomString(int length) {
		String base = "abcdefghijklmnopqrstuvwxyz0123456789";
		Random random = new Random();
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < length; ++i) {
			int number = random.nextInt(base.length());
			sb.append(base.charAt(number));
		}

		return sb.toString();
	}

	public String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip != null && ip.indexOf(",") > -1 && ip.length() > 8) {
			ip = ip.substring(0, ip.indexOf(","));
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}

		return ip;
	}





	public Object getValueFromMeta(MetaObject meta, String propertyName) {
		try {
			return meta.getValue(propertyName);
		} catch (Exception var4) {
			return null;
		}
	}

	public <T> T getValue(Object sourceObject, String name) {
		try {
			MetaObject targetMeta = SystemMetaObject.forObject(sourceObject);
			return (T) targetMeta.getValue(name);
		} catch (Exception var4) {
			return null;
		}
	}

	public String lpad(String str, int size, String padStr) {
		String val = StringUtils.leftPad(str, size, padStr);
		if (size > 0 && val.length() > size) {
			val = val.substring(val.length() - size, val.length());
		}

		return val;
	}

	public String rpad(String str, int size, String padStr) {
        String val = StringUtils.rightPad(str, size, padStr);
        if (size > 0 && val.length() > size) {
            val = val.substring(val.length() - size, val.length());
        }

        return val;
	}
}